//
//  DR_PDFTool.swift
//  DocReaderRP
//
//  Created by  mac on 2025/11/14.
//

import UIKit
import PDFKit

// MARK: - PDF 文件模型
struct DR_PDFFileModel {
    let fileName: String
    let fileURL: URL
    let fileSize: Int64
    let createDate: Date
    let pageCount: Int
    
    var displayName: String {
        return fileName.replacingOccurrences(of: ".pdf", with: "")
    }
    
    var fileSizeString: String {
        return formatFileSize(fileSize)
    }
    
    private func formatFileSize(_ bytes: Int64) -> String {
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = [.useKB, .useMB]
        formatter.countStyle = .file
        return formatter.string(fromByteCount: bytes)
    }
}

// MARK: - PDF 工具类
class DR_PDFTool {
    
    static let shared = DR_PDFTool()
    
    // PDF 文件保存目录
    private var pdfDirectoryURL: URL {
        let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let pdfPath = documentsPath.appendingPathComponent("PDFs", isDirectory: true)
        
        // 确保目录存在
        if !FileManager.default.fileExists(atPath: pdfPath.path) {
            try? FileManager.default.createDirectory(at: pdfPath, withIntermediateDirectories: true, attributes: nil)
        }
        
        return pdfPath
    }
    
    private init() {}
    
    // MARK: - 通过图片生成 PDF 并保存
    /// 通过图片数组生成 PDF 并保存到本地
    /// - Parameters:
    ///   - images: 图片数组
    ///   - fileName: PDF 文件名（不包含 .pdf 扩展名），如果为 nil，则根据第一张图片名生成
    ///   - pageSize: PDF 页面大小，默认为 A4
    /// - Returns: 保存成功的 PDF 文件模型，失败返回 nil
    func createPDF(from images: [UIImage], fileName: String? = nil, pageSize: CGSize = CGSize(width: 612, height: 792)) -> DR_PDFFileModel? {
        guard !images.isEmpty else {
            print("⚠️ [DR_PDFTool] 图片数组为空")
            return nil
        }
        
        // 生成 PDF 文档
        let pdfDocument = PDFDocument()
        
        for (index, image) in images.enumerated() {
            // 调整图片大小以适应 PDF 页面
            let scaledImage = scaleImage(image, toFit: pageSize)
            
            // 创建 PDF 页面
            if let pdfPage = PDFPage(image: scaledImage) {
                pdfDocument.insert(pdfPage, at: index)
            }
        }
        
        // 生成文件名
        let finalFileName = generateFileName(from: fileName, firstImage: images.first)
        
        // 保存 PDF
        return savePDF(pdfDocument, fileName: finalFileName)
    }
    
    // MARK: - 保存 PDF 到本地
    private func savePDF(_ pdfDocument: PDFDocument, fileName: String) -> DR_PDFFileModel? {
        let fileURL = pdfDirectoryURL.appendingPathComponent("\(fileName).pdf")
        
        // 如果文件已存在，添加时间戳后缀
        let finalURL = ensureUniqueFileName(fileURL)
        let finalFileName = finalURL.deletingPathExtension().lastPathComponent
        
        // 保存 PDF
        guard pdfDocument.write(to: finalURL) else {
            print("❌ [DR_PDFTool] PDF 保存失败: \(finalURL.path)")
            return nil
        }
        
        // 获取文件信息
        guard let attributes = try? FileManager.default.attributesOfItem(atPath: finalURL.path),
              let fileSize = attributes[.size] as? Int64,
              let createDate = attributes[.creationDate] as? Date else {
            print("⚠️ [DR_PDFTool] 无法获取文件属性")
            return nil
        }
        
        let model = DR_PDFFileModel(
            fileName: "\(finalFileName).pdf",
            fileURL: finalURL,
            fileSize: fileSize,
            createDate: createDate,
            pageCount: pdfDocument.pageCount
        )
        
        print("✅ [DR_PDFTool] PDF 保存成功: \(finalURL.path)")
        return model
    }
    
    // MARK: - 生成文件名
    private func generateFileName(from customName: String?, firstImage: UIImage?) -> String {
        if let customName = customName, !customName.isEmpty {
            return sanitizeFileName(customName)
        }
        
        // 如果有图片，尝试从图片名生成（如果图片来自相册）
        // 否则使用默认名称
        let defaultName = "ImageToPDF_\(Date().timeIntervalSince1970)"
        return sanitizeFileName(defaultName)
    }
    
    // MARK: - 清理文件名（移除非法字符）
    private func sanitizeFileName(_ fileName: String) -> String {
        let invalidChars = CharacterSet(charactersIn: "/\\?%*|\"<>")
        return fileName.components(separatedBy: invalidChars).joined(separator: "_")
    }
    
    // MARK: - 确保文件名唯一
    private func ensureUniqueFileName(_ url: URL) -> URL {
        var finalURL = url
        var counter = 1
        
        while FileManager.default.fileExists(atPath: finalURL.path) {
            let fileName = url.deletingPathExtension().lastPathComponent
            let newFileName = "\(fileName)_\(counter)"
            finalURL = url.deletingLastPathComponent().appendingPathComponent("\(newFileName).pdf")
            counter += 1
        }
        
        return finalURL
    }
    
    // MARK: - 缩放图片以适应页面
    private func scaleImage(_ image: UIImage, toFit size: CGSize) -> UIImage {
        let imageSize = image.size
        let widthRatio = size.width / imageSize.width
        let heightRatio = size.height / imageSize.height
        let scaleFactor = min(widthRatio, heightRatio)
        
        let scaledWidth = imageSize.width * scaleFactor
        let scaledHeight = imageSize.height * scaleFactor
        
        UIGraphicsBeginImageContextWithOptions(CGSize(width: scaledWidth, height: scaledHeight), false, 0.0)
        image.draw(in: CGRect(x: 0, y: 0, width: scaledWidth, height: scaledHeight))
        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return scaledImage ?? image
    }
    
    // MARK: - 获取所有 PDF 文件
    /// 获取本地保存的所有 PDF 文件列表
    /// - Returns: PDF 文件模型数组，按创建时间倒序排列
    func getAllPDFFiles() -> [DR_PDFFileModel] {
        guard let fileURLs = try? FileManager.default.contentsOfDirectory(
            at: pdfDirectoryURL,
            includingPropertiesForKeys: [.fileSizeKey, .creationDateKey],
            options: [.skipsHiddenFiles]
        ) else {
            return []
        }
        
        let pdfFiles = fileURLs
            .filter { $0.pathExtension.lowercased() == "pdf" }
            .compactMap { url -> DR_PDFFileModel? in
                guard let attributes = try? FileManager.default.attributesOfItem(atPath: url.path),
                      let fileSize = attributes[.size] as? Int64,
                      let createDate = attributes[.creationDate] as? Date else {
                    return nil
                }
                
                // 读取 PDF 获取页数
                let pageCount = getPDFPageCount(url: url)
                
                return DR_PDFFileModel(
                    fileName: url.lastPathComponent,
                    fileURL: url,
                    fileSize: fileSize,
                    createDate: createDate,
                    pageCount: pageCount
                )
            }
            .sorted { $0.createDate > $1.createDate } // 按创建时间倒序
        
        return pdfFiles
    }
    
    // MARK: - 获取 PDF 页数
    private func getPDFPageCount(url: URL) -> Int {
        guard let pdfDocument = PDFDocument(url: url) else {
            return 0
        }
        return pdfDocument.pageCount
    }
    
    // MARK: - 重命名 PDF
    /// 重命名 PDF 文件
    /// - Parameters:
    ///   - oldFileURL: 原文件 URL
    ///   - newName: 新文件名（不包含 .pdf 扩展名）
    /// - Returns: 重命名后的文件模型，失败返回 nil
    func renamePDF(oldFileURL: URL, newName: String) -> DR_PDFFileModel? {
        let sanitizedName = sanitizeFileName(newName)
        let newURL = oldFileURL.deletingLastPathComponent().appendingPathComponent("\(sanitizedName).pdf")
        
        // 检查新文件名是否已存在
        if FileManager.default.fileExists(atPath: newURL.path) {
            print("⚠️ [DR_PDFTool] 文件名已存在: \(newURL.path)")
            return nil
        }
        
        // 重命名文件
        do {
            // 如果原文件有密码，需要迁移密码信息
            let oldKey = getFileIdentifier(for: oldFileURL)
            let oldPassword = UserDefaults.standard.string(forKey: "PDF_PASSWORD_\(oldKey)")
            
            try FileManager.default.moveItem(at: oldFileURL, to: newURL)
            
            // 迁移密码信息
            if let password = oldPassword {
                let newKey = getFileIdentifier(for: newURL)
                UserDefaults.standard.set(password, forKey: "PDF_PASSWORD_\(newKey)")
                UserDefaults.standard.removeObject(forKey: "PDF_PASSWORD_\(oldKey)")
                UserDefaults.standard.synchronize()
            }
            
            // 获取文件信息
            guard let attributes = try? FileManager.default.attributesOfItem(atPath: newURL.path),
                  let fileSize = attributes[.size] as? Int64,
                  let createDate = attributes[.creationDate] as? Date else {
                return nil
            }
            
            let pageCount = getPDFPageCount(url: newURL)
            
            let model = DR_PDFFileModel(
                fileName: "\(sanitizedName).pdf",
                fileURL: newURL,
                fileSize: fileSize,
                createDate: createDate,
                pageCount: pageCount
            )
            
            print("✅ [DR_PDFTool] PDF 重命名成功: \(newURL.path)")
            return model
        } catch {
            print("❌ [DR_PDFTool] PDF 重命名失败: \(error.localizedDescription)")
            return nil
        }
    }
    
    // MARK: - PDF 密码管理
    /// 获取文件的唯一标识符（用于密码存储）
    /// 使用文件名+文件大小+创建日期作为唯一标识，避免路径变化导致密码丢失
    private func getFileIdentifier(for fileURL: URL) -> String {
        // 获取文件属性
        guard let attributes = try? FileManager.default.attributesOfItem(atPath: fileURL.path),
              let fileSize = attributes[.size] as? Int64,
              let createDate = attributes[.creationDate] as? Date else {
            // 如果无法获取属性，回退到使用标准化路径
            return fileURL.standardizedFileURL.path
        }
        
        // 使用文件名+文件大小+创建时间戳作为唯一标识
        let fileName = fileURL.lastPathComponent
        let timestamp = String(format: "%.0f", createDate.timeIntervalSince1970)
        let identifier = "\(fileName)_\(fileSize)_\(timestamp)"
        
        return identifier
    }
    
    /// 为 PDF 设置密码
    /// - Parameters:
    ///   - fileURL: PDF 文件 URL
    ///   - password: 密码
    /// - Returns: 是否设置成功
    func setPassword(for fileURL: URL, password: String) -> Bool {
        let key = getFileIdentifier(for: fileURL)
        UserDefaults.standard.set(password, forKey: "PDF_PASSWORD_\(key)")
        // 确保立即同步到磁盘
        UserDefaults.standard.synchronize()
        print("✅ [DR_PDFTool] PDF 密码设置成功: \(fileURL.lastPathComponent), key: \(key)")
        return true
    }
    
    /// 检查 PDF 是否有密码
    /// - Parameter fileURL: PDF 文件 URL
    /// - Returns: 是否有密码
    func hasPassword(for fileURL: URL) -> Bool {
        let key = getFileIdentifier(for: fileURL)
        let hasPassword = UserDefaults.standard.string(forKey: "PDF_PASSWORD_\(key)") != nil
        print("🔍 [DR_PDFTool] 检查密码: \(fileURL.lastPathComponent), key: \(key), hasPassword: \(hasPassword)")
        return hasPassword
    }
    
    /// 验证 PDF 密码
    /// - Parameters:
    ///   - fileURL: PDF 文件 URL
    ///   - password: 输入的密码
    /// - Returns: 密码是否正确
    func verifyPassword(for fileURL: URL, password: String) -> Bool {
        let key = getFileIdentifier(for: fileURL)
        guard let savedPassword = UserDefaults.standard.string(forKey: "PDF_PASSWORD_\(key)") else {
            return false
        }
        return savedPassword == password
    }
    
    /// 移除 PDF 密码
    /// - Parameter fileURL: PDF 文件 URL
    /// - Returns: 是否移除成功
    func removePassword(for fileURL: URL) -> Bool {
        let key = getFileIdentifier(for: fileURL)
        UserDefaults.standard.removeObject(forKey: "PDF_PASSWORD_\(key)")
        // 确保立即同步到磁盘
        UserDefaults.standard.synchronize()
        print("✅ [DR_PDFTool] PDF 密码已移除: \(fileURL.lastPathComponent), key: \(key)")
        return true
    }
    
    // MARK: - 删除 PDF
    /// 删除指定的 PDF 文件
    /// - Parameter fileURL: PDF 文件 URL
    /// - Returns: 是否删除成功
    @discardableResult
    func deletePDF(fileURL: URL) -> Bool {
        do {
            // 删除文件时同时删除密码
            removePassword(for: fileURL)
            
            try FileManager.default.removeItem(at: fileURL)
            print("✅ [DR_PDFTool] PDF 删除成功: \(fileURL.path)")
            return true
        } catch {
            print("❌ [DR_PDFTool] PDF 删除失败: \(error.localizedDescription)")
            return false
        }
    }
    
    // MARK: - 获取 PDF 文档（用于预览）
    /// 获取 PDF 文档对象，用于预览
    /// - Parameter fileURL: PDF 文件 URL
    /// - Returns: PDFDocument 对象，失败返回 nil
    func getPDFDocument(fileURL: URL) -> PDFDocument? {
        return PDFDocument(url: fileURL)
    }
    
    // MARK: - 获取 PDF 预览图
    /// 获取 PDF 第一页的预览图
    /// - Parameters:
    ///   - fileURL: PDF 文件 URL
    ///   - size: 预览图大小
    /// - Returns: 预览图，失败返回 nil
    func getPDFThumbnail(fileURL: URL, size: CGSize = CGSize(width: 200, height: 200)) -> UIImage? {
        guard let pdfDocument = PDFDocument(url: fileURL),
              let firstPage = pdfDocument.page(at: 0) else {
            return nil
        }
        
        let pageRect = firstPage.bounds(for: .mediaBox)
        let scale = min(size.width / pageRect.width, size.height / pageRect.height)
        let scaledSize = CGSize(width: pageRect.width * scale, height: pageRect.height * scale)
        
        return firstPage.thumbnail(of: scaledSize, for: .mediaBox)
    }
    
    // MARK: - 提取 PDF 所有页面为图片
    /// 提取 PDF 所有页面为图片数组
    /// - Parameter fileURL: PDF 文件 URL
    /// - Returns: 图片数组，每个元素对应一页
    func extractPDFPagesAsImages(fileURL: URL) -> [UIImage] {
        guard let pdfDocument = PDFDocument(url: fileURL) else {
            print("❌ [DR_PDFTool] 无法打开PDF文件: \(fileURL.path)")
            return []
        }
        
        var images: [UIImage] = []
        
        for pageIndex in 0..<pdfDocument.pageCount {
            guard let page = pdfDocument.page(at: pageIndex) else {
                continue
            }
            
            let pageRect = page.bounds(for: .mediaBox)
            let renderer = UIGraphicsImageRenderer(size: pageRect.size)
            
            let image = renderer.image { context in
                // 设置白色背景
                UIColor.white.setFill()
                context.fill(CGRect(origin: .zero, size: pageRect.size))
                
                // 渲染PDF页面
                context.cgContext.translateBy(x: 0, y: pageRect.size.height)
                context.cgContext.scaleBy(x: 1.0, y: -1.0)
                page.draw(with: .mediaBox, to: context.cgContext)
            }
            
            images.append(image)
        }
        
        print("✅ [DR_PDFTool] 成功提取 \(images.count) 页图片")
        return images
    }
    
    // MARK: - 从选中的页面创建新PDF
    /// 从选中的页面索引创建新的PDF文件
    /// - Parameters:
    ///   - sourceFileURL: 源PDF文件URL
    ///   - selectedPageIndices: 选中的页面索引数组（从0开始）
    ///   - fileName: 新PDF文件名（不包含扩展名），如果为nil则自动生成
    /// - Returns: 创建成功的PDF文件模型，失败返回nil
    func createPDFFromSelectedPages(sourceFileURL: URL, selectedPageIndices: [Int], fileName: String? = nil) -> DR_PDFFileModel? {
        guard let pdfDocument = PDFDocument(url: sourceFileURL) else {
            print("❌ [DR_PDFTool] 无法打开源PDF文件")
            return nil
        }
        
        guard !selectedPageIndices.isEmpty else {
            print("⚠️ [DR_PDFTool] 未选择任何页面")
            return nil
        }
        
        // 提取选中的页面为图片
        var selectedImages: [UIImage] = []
        for pageIndex in selectedPageIndices.sorted() {
            guard pageIndex >= 0 && pageIndex < pdfDocument.pageCount,
                  let page = pdfDocument.page(at: pageIndex) else {
                print("⚠️ [DR_PDFTool] 页面索引超出范围: \(pageIndex)")
                continue
            }
            
            let pageRect = page.bounds(for: .mediaBox)
            let renderer = UIGraphicsImageRenderer(size: pageRect.size)
            
            let image = renderer.image { context in
                // 设置白色背景
                UIColor.white.setFill()
                context.fill(CGRect(origin: .zero, size: pageRect.size))
                
                // 渲染PDF页面
                context.cgContext.translateBy(x: 0, y: pageRect.size.height)
                context.cgContext.scaleBy(x: 1.0, y: -1.0)
                page.draw(with: .mediaBox, to: context.cgContext)
            }
            
            selectedImages.append(image)
        }
        
        guard !selectedImages.isEmpty else {
            print("❌ [DR_PDFTool] 未能提取任何页面图片")
            return nil
        }
        
        // 生成文件名
        let sourceFileName = sourceFileURL.deletingPathExtension().lastPathComponent
        let finalFileName = fileName ?? "\(sourceFileName)_split_\(Date().timeIntervalSince1970)"
        
        // 从图片创建PDF
        return createPDF(from: selectedImages, fileName: finalFileName)
    }
    
    // MARK: - 合并多个PDF文件
    /// 合并多个PDF文件为一个新的PDF文件
    /// - Parameters:
    ///   - pdfFileURLs: 要合并的PDF文件URL数组（按顺序合并）
    ///   - fileName: 新PDF文件名（不包含 .pdf 扩展名），如果为 nil 则自动生成
    /// - Returns: 合并成功的PDF文件模型，失败返回 nil
    func mergePDFs(pdfFileURLs: [URL], fileName: String? = nil) -> DR_PDFFileModel? {
        guard !pdfFileURLs.isEmpty else {
            print("⚠️ [DR_PDFTool] PDF文件数组为空")
            return nil
        }
        
        // 使用NSMutableData和CGDataConsumer创建新的PDF
        let pdfData = NSMutableData()
        guard let dataConsumer = CGDataConsumer(data: pdfData as CFMutableData) else {
            print("❌ [DR_PDFTool] 无法创建数据消费者")
            return nil
        }
        
        var mediaBox = CGRect(x: 0, y: 0, width: 612, height: 792) // 默认A4大小
        guard let pdfContext = CGContext(consumer: dataConsumer, mediaBox: &mediaBox, nil) else {
            print("❌ [DR_PDFTool] 无法创建PDF上下文")
            return nil
        }
        
        // 按顺序合并所有PDF文件
        for (fileIndex, fileURL) in pdfFileURLs.enumerated() {
            guard let sourcePDF = PDFDocument(url: fileURL) else {
                print("⚠️ [DR_PDFTool] 无法打开PDF文件: \(fileURL.lastPathComponent)")
                continue
            }
            
            // 将源PDF的所有页面添加到合并后的PDF中
            for pageIndex in 0..<sourcePDF.pageCount {
                guard let sourcePage = sourcePDF.page(at: pageIndex) else {
                    continue
                }
                
                // 获取页面尺寸
                let pageRect = sourcePage.bounds(for: .mediaBox)
                var mutablePageRect = pageRect
                
                // 开始新页面
                pdfContext.beginPage(mediaBox: &mutablePageRect)
                
                // 绘制页面内容
                sourcePage.draw(with: .mediaBox, to: pdfContext)
                
                // 结束页面
                pdfContext.endPage()
            }
            
            print("✅ [DR_PDFTool] 已合并文件 \(fileIndex + 1)/\(pdfFileURLs.count): \(fileURL.lastPathComponent)")
        }
        
        // 关闭PDF上下文
        pdfContext.closePDF()
        
        // 从数据创建PDFDocument
        guard let mergedPDFDocument = PDFDocument(data: pdfData as Data) else {
            print("❌ [DR_PDFTool] 无法从数据创建PDF文档")
            return nil
        }
        
        guard mergedPDFDocument.pageCount > 0 else {
            print("❌ [DR_PDFTool] 合并后的PDF为空")
            return nil
        }
        
        // 生成文件名
        let finalFileName: String
        if let customName = fileName, !customName.isEmpty {
            finalFileName = sanitizeFileName(customName)
        } else {
            let timestamp = Date().timeIntervalSince1970
            finalFileName = "MergedPDF_\(timestamp)"
        }
        
        // 保存合并后的PDF
        print("✅ [DR_PDFTool] 合并完成，共 \(mergedPDFDocument.pageCount) 页")
        return savePDF(mergedPDFDocument, fileName: finalFileName)
    }
}
